﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

//
// Optimal documentation http://support.optimalpayments.com/REPOSITORY/WebServices_API_1.0.pdf
//

namespace OnlinePayments
{
    internal class OptimalPayments : PaymentProcessor
    {
        Dictionary<string, string> countries = new Dictionary<string, string>();
        Dictionary<string, string> states = new Dictionary<string, string>();

        private string _accountNum;
        private string _storeID;
        private string _password;

        public OptimalPayments(SqlConnection conn, char processorCode, int ownerID)
            : base(conn, processorCode, ownerID)
        {
            SqlCommand cmm = conn.CreateCommand();

            _accountNum = _configStrings["AccountNum"];
            _storeID = _configStrings["StoreID"];
            _password = _configStrings["Password"];

            if (_accountNum == null || _storeID == null || _password == null)
                throw new Exception("Missing data in the OptimalPayments config section. (AccountNum, StoreID, Password).");

            // Build a lookup to find the country code for country names.
            cmm.CommandText = "select name, CountryCode, CountryCode3 from codeCountry where Active = 1";
            SqlDataReader rdr = cmm.ExecuteReader();
            while (rdr.Read())
            {
                countries.Add(rdr.GetString(0), rdr.GetString(1));
                countries.Add(rdr.GetString(1), rdr.GetString(1));
                countries.Add(rdr.GetString(2), rdr.GetString(1));
            }
            rdr.Close();

            // Build a lookup to find the state code for state names.
            cmm.CommandText = "select abbrev, name from codeState";
            rdr = cmm.ExecuteReader();
            while (rdr.Read())
            {
                states.Add(rdr.GetString(0), rdr.GetString(0));
                states.Add(rdr.GetString(1), rdr.GetString(0));
            }
            rdr.Close();
        }

        public override char Authorize(CustomerInfo customerInfo, int transactionID, decimal amount, out string responseCode, out string responseText, out string AVSResult, out string CVV2Response, out string processorTransactionID, out string authCode)
        {
            Optimal.CCAuthRequestV1 auth = new Optimal.CCAuthRequestV1();
            Optimal.MerchantAccountV1 account = new Optimal.MerchantAccountV1();
            account.accountNum = _accountNum;
            account.storeID = _storeID;
            account.storePwd = _password;

            auth.merchantAccount = account;
            auth.merchantRefNum = transactionID.ToString();
            auth.amount = amount.ToString("#0.00");
            Optimal.CardV1 card = new Optimal.CardV1();
            card.cardNum = customerInfo.CardNumber;
            Optimal.CardExpiryV1 expir = new Optimal.CardExpiryV1();
            expir.month = int.Parse(customerInfo.CardExpiration.Substring(0, 2));
            expir.year = 2000 + int.Parse(customerInfo.CardExpiration.Substring(2));
            card.cardExpiry = expir;
            //card.cardType = Optimal.CardTypeV1.VI;
            card.cardTypeSpecified = false;
            card.cvd = customerInfo.CVV2;
            card.cvdIndicator = 1;
            card.cvdIndicatorSpecified = true;
            auth.card = card;
            Optimal.BillingDetailsV1 billing = new Optimal.BillingDetailsV1();
            billing.cardPayMethodSpecified = true;
            billing.cardPayMethod = Optimal.CardPayMethodV1.TEL;
            billing.city = customerInfo.City;
            billing.countrySpecified = false;
            if (countries.ContainsKey(customerInfo.Country))
            {
                Optimal.CountryV1 country;
                if (Enum.TryParse<Optimal.CountryV1>(countries[customerInfo.Country], out country))
                {
                    billing.country = country;
                    billing.countrySpecified = true;
                }
            }
            billing.firstName = customerInfo.FirstName;
            billing.lastName = customerInfo.LastName;
            billing.street = customerInfo.Address;
            billing.zip = customerInfo.Zip;
            if (states.ContainsKey(customerInfo.State))
            {
                Optimal.StateV1 state;
                if (Enum.TryParse<Optimal.StateV1>(states[customerInfo.State], out state))
                {
                    billing.Item = (object)state;
                }
            }
            billing.phone = string.Empty;
            billing.email = string.Empty;

            auth.billingDetails = billing;
            auth.productType = Optimal.ProductTypeV1.P;
            auth.productTypeSpecified = true;

            Optimal.CCTxnResponseV1 resp;
            Optimal.CreditCardServiceV1PortTypeClient pt = new Optimal.CreditCardServiceV1PortTypeClient();
            resp = pt.ccAuthorize(auth);

            responseCode = resp.code.ToString();
            responseText = resp.description;
            AVSResult = Enum.GetName(typeof(Optimal.AvsResponseV1), resp.avsResponse);
            CVV2Response = Enum.GetName(typeof(Optimal.AvsResponseV1), resp.cvdResponse);
            processorTransactionID = resp.confirmationNumber;
            authCode = resp.authCode;

            return (Enum.GetName(typeof(Optimal.DecisionV1), resp.decision)[0]);
        }

        public override char CancelAuthorization(Int32 transactionID,
            string processorTransactionID,
            decimal amount,
            out string responseCode,
            out string responseText
            )
        {
            Optimal.CCAuthReversalRequestV1 authReversalRequest = new Optimal.CCAuthReversalRequestV1();
            Optimal.MerchantAccountV1 account = new Optimal.MerchantAccountV1();
            account.accountNum = _accountNum;
            account.storeID = _storeID;
            account.storePwd = _password;
            authReversalRequest.merchantAccount = account;

            authReversalRequest.confirmationNumber = processorTransactionID;
            authReversalRequest.merchantRefNum = transactionID.ToString();
            authReversalRequest.reversalAmount = amount.ToString("#0.00");

            Optimal.CreditCardServiceV1PortTypeClient pt = new Optimal.CreditCardServiceV1PortTypeClient();
            Optimal.CCTxnResponseV1 resp = pt.ccAuthorizeReversal(authReversalRequest);

            responseCode = resp.code.ToString();
            responseText = resp.description;

            return (Enum.GetName(typeof(Optimal.DecisionV1), resp.decision)[0]);
        }

        public override char Deposit(CustomerInfo customerInfo, int transactionID, decimal amount, out string responseCode, out string responseText, out string AVSResult, out string CVV2Response, out string processorTransactionID)
        {
            throw new NotImplementedException();
        }

        public override char DepositWithPriorAuth(CustomerInfo customerInfo, int transactionID, decimal amount, string processorTransactionID, string authCode, out string responseCode, out string responseText)
        {
            throw new NotImplementedException();
        }

        public override char Refund(CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            string priorProcessorTransactionID,
            out string responseCode,
            out string responseText,
            out string processorTransactionID
            )
        {
            throw new NotImplementedException();
        }
    }
}
